﻿using System;
using System.Collections.Generic;

namespace machines_lib
{
    public abstract class TuringMachine: IStateMachine
    {
        public const char NULL_CHAR = '\0';

        private HashSet<MachineState> stateAlphabet;
        private HashSet<MachineState> finalStates;
        private MachineState initialState;

        private HashSet<char> tapeAlphabet;
        private char blankSymbol;

        /// <summary>
        /// Call the Turing Machine's transition function to determine
        /// the next action
        /// </summary>
        /// <param name="x">The input state & character for the machine</param>
        /// <returns>The corresponding output (next) state, character to write, and
        /// direction to move, as defined by the machine's transition function</returns>
        public abstract TMOutput Transition(TMInput x);

        /// <summary>
        /// Get or set the state alphabet of the machine.
        /// Must be a superset of FinalStates.
        /// (Equivalent to TuringMachine.State)
        /// </summary>
        public HashSet<MachineState> StateAlphabet
        {
            get { return stateAlphabet; }
            set { stateAlphabet = value; }
        }

        /// <summary>
        /// Get or set the machine's terminal states.
        /// Must be a subset of StateAlphabet.
        /// </summary>
        public HashSet<MachineState> FinalStates
        {
            get { return finalStates; }
            set { finalStates = value; }
        }

        /// <summary>
        /// Get or set the machine's initial state.
        /// Must be an element of StateAlphabet.
        /// </summary>
        public MachineState InitialState
        {
            get { return initialState; }
            set { initialState = value; }
        }

        /// <summary>
        /// Get or set the machine's tape alphabet
        /// - the set of symbols allowed to appear as input.
        /// Must include the "blank" symbol.
        /// </summary>
        public HashSet<char> TapeAlphabet
        {
            get { return tapeAlphabet; }
            set { tapeAlphabet = value; }
        }

        /// <summary>
        /// Get or set the machine's "blank" symbol -
        /// the symbol which is assumed to appear infinitely in both directions
        /// on the tape until it is overwritten. Must be an element of TapeAlphabet.
        /// </summary>
        public char BlankSymbol;

        #region IStateMachine Members

        public ICollection<MachineState> States
        {
            get
            {
                return stateAlphabet;
            }
            set
            {
                stateAlphabet = new HashSet<MachineState>(value);
            }
        }

        #endregion
    }
}
